#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
中央任务调度系统模块
"""

import uuid
import logging
import datetime
from typing import Dict, List, Optional, Any
from .database import Database
from .models import Task, TaskStatus
from .queue_manager import QueueManager


class TaskScheduler:
    """中央任务调度器，负责管理所有任务的创建和队列分配"""
    
    _instance = None
    
    def __new__(cls, database=None, config=None):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._init_scheduler(database, config)
        return cls._instance
        
    def stop(self):
        """停止任务调度器"""
        # 停止所有队列处理
        if hasattr(self, 'queue_manager') and self.queue_manager:
            # 如果队列管理器有stop方法，调用它
            if hasattr(self.queue_manager, 'stop'):
                self.queue_manager.stop()
        
        # 记录日志
        if hasattr(self, 'logger'):
            self.logger.info("任务调度器已停止")
    
    def _init_scheduler(self, database, config):
        """初始化调度器
        
        Args:
            database: 数据库实例
            config: 配置信息
        """
        self.database = database
        self.config = config
        self.queue_manager = QueueManager()
        self.logger = logging.getLogger(__name__)
        self.logger.info("任务调度器已初始化")
    
    def create_task(self, task_data: Dict) -> Task:
        """创建新任务
        
        Args:
            task_data: 任务数据字典，包含以下字段：
                - name: 任务名称
                - script_id: 脚本ID
                - trigger_id: 触发器ID (可选)
                - params: 脚本参数 (可选)
                - priority: 优先级 (可选，默认为5)
        
        Returns:
            Task: 创建的任务对象
        """
        session = self.database.get_session()
        try:
            # 验证脚本是否存在
            script = self.database.get_script_by_id(task_data['script_id'])
            if not script:
                raise ValueError(f"脚本不存在: {task_data['script_id']}")
            
            # 创建任务
            task = Task(
                id=str(uuid.uuid4()),
                name=task_data['name'],
                script_id=task_data['script_id'],
                trigger_id=task_data.get('trigger_id'),
                params=task_data.get('params', {}),
                priority=task_data.get('priority', 5),
                status=TaskStatus.PENDING.value
            )
            
            session.add(task)
            session.commit()
            
            # 将任务添加到队列
            self._add_task_to_queue(task)
            
            self.logger.info(f"已创建任务: {task.name} (ID: {task.id})")
            return task
        except Exception as e:
            session.rollback()
            self.logger.error(f"创建任务失败: {str(e)}")
            raise e
        finally:
            session.close()
    
    def _add_task_to_queue(self, task: Task) -> None:
        """将任务添加到队列
        
        Args:
            task: 任务对象
        """
        # 构建队列项数据
        queue_item = {
            "id": task.id,
            "name": task.name,
            "script_id": task.script_id,
            "priority": task.priority,
            "status": task.status,
            "created_at": task.created_at.timestamp() if task.created_at else None
        }
        
        # 添加到队列管理器
        self.queue_manager.add_item(task.id, queue_item)
        self.logger.info(f"已将任务添加到队列: {task.name} (ID: {task.id})")
    
    def get_task(self, task_id: str) -> Optional[Task]:
        """获取任务
        
        Args:
            task_id: 任务ID
        
        Returns:
            Task: 任务对象，如果不存在则返回None
        """
        session = self.database.get_session()
        try:
            task = session.query(Task).filter(Task.id == task_id).first()
            return task
        finally:
            session.close()
    
    def get_tasks(self, status=None, limit=100) -> List[Task]:
        """获取任务列表
        
        Args:
            status: 任务状态过滤
            limit: 返回结果数量限制
        
        Returns:
            List[Task]: 任务对象列表
        """
        session = self.database.get_session()
        try:
            query = session.query(Task)
            if status:
                query = query.filter(Task.status == status)
            
            query = query.order_by(Task.created_at.desc()).limit(limit)
            return query.all()
        finally:
            session.close()
    
    def update_task_status(self, task_id: str, status: str, log=None, result=None) -> bool:
        """更新任务状态
        
        Args:
            task_id: 任务ID
            status: 新状态
            log: 任务日志 (可选)
            result: 任务结果 (可选)
        
        Returns:
            bool: 是否更新成功
        """
        session = self.database.get_session()
        try:
            task = session.query(Task).filter(Task.id == task_id).first()
            if not task:
                self.logger.warning(f"更新任务状态失败，任务不存在: {task_id}")
                return False
            
            # 更新状态
            old_status = task.status
            task.status = status
            
            # 更新日志和结果
            if log is not None:
                task.log = log
            
            if result is not None:
                task.result = result
            
            # 更新时间
            if status == TaskStatus.RUNNING.value and old_status != TaskStatus.RUNNING.value:
                task.start_time = datetime.datetime.now()
            
            if status in [TaskStatus.COMPLETED.value, TaskStatus.FAILED.value, TaskStatus.CANCELLED.value]:
                task.end_time = datetime.datetime.now()
            
            session.commit()
            
            # 更新队列中的任务状态
            self._update_queue_task_status(task_id, status)
            
            self.logger.info(f"已更新任务状态: {task.name} (ID: {task.id}) {old_status} -> {status}")
            return True
        except Exception as e:
            session.rollback()
            self.logger.error(f"更新任务状态失败: {str(e)}")
            return False
        finally:
            session.close()
    
    def _update_queue_task_status(self, task_id: str, status: str) -> None:
        """更新队列中的任务状态
        
        Args:
            task_id: 任务ID
            status: 新状态
        """
        try:
            # 获取队列项
            queue_item = self.queue_manager.queue.get(task_id)
            if queue_item:
                # 更新状态
                queue_item["status"] = status
                
                # 如果任务已完成或失败，从队列中移除
                if status in [TaskStatus.COMPLETED.value, TaskStatus.FAILED.value, TaskStatus.CANCELLED.value]:
                    self.queue_manager.remove_item(task_id)
                    self.logger.info(f"已从队列中移除任务: {task_id}")
        except Exception as e:
            self.logger.error(f"更新队列任务状态失败: {str(e)}")
    
    def cancel_task(self, task_id: str) -> bool:
        """取消任务
        
        Args:
            task_id: 任务ID
        
        Returns:
            bool: 是否取消成功
        """
        return self.update_task_status(task_id, TaskStatus.CANCELLED.value, log="任务已被用户取消")
    
    def get_next_task(self) -> Optional[Task]:
        """获取下一个待执行的任务
        
        Returns:
            Task: 任务对象，如果没有待执行任务则返回None
        """
        session = self.database.get_session()
        try:
            # 按优先级获取下一个待执行任务
            task = session.query(Task).filter(
                Task.status == TaskStatus.PENDING.value
            ).order_by(Task.priority.desc(), Task.created_at.asc()).first()
            
            return task
        finally:
            session.close()
    
    def get_task_count(self, status=None) -> int:
        """获取任务数量
        
        Args:
            status: 任务状态过滤
        
        Returns:
            int: 任务数量
        """
        session = self.database.get_session()
        try:
            query = session.query(Task)
            if status:
                query = query.filter(Task.status == status)
            
            return query.count()
        finally:
            session.close()